home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DJLSR106.ARJ / RNG.CC < prev    next >
C/C++ Source or Header  |  1992-03-30  |  4KB  |  137 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /* 
  3. Copyright (C) 1989 Free Software Foundation
  4.  
  5. This file is part of the GNU C++ Library.  This library is free
  6. software; you can redistribute it and/or modify it under the terms of
  7. the GNU Library General Public License as published by the Free
  8. Software Foundation; either version 2 of the License, or (at your
  9. option) any later version.  This library is distributed in the hope
  10. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  11. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE.  See the GNU Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #ifdef __GNUG__
  18. #pragma implementation "RNG.h"
  19. #endif
  20. #include <values.h>
  21. #include <assert.h>
  22. #include <builtin.h>
  23. #include <RNG.h>
  24.  
  25. // these get initialized right in the ctors, but need default value in C++
  26. // (even if trash, as here)
  27.  
  28. PrivateRNGSingleType PrivateRNGSingleTypeInit;
  29. PrivateRNGDoubleType PrivateRNGDoubleTypeInit;
  30. PrivateRNGSingleType RNG::singleMantissa = PrivateRNGSingleTypeInit;
  31. PrivateRNGDoubleType RNG::doubleMantissa = PrivateRNGDoubleTypeInit;
  32.  
  33. //
  34. //    The scale constant is 2^-31. It is used to scale a 31 bit
  35. //    long to a double.
  36. //
  37.  
  38. //static const double randomDoubleScaleConstant = 4.656612873077392578125e-10;
  39. //static const float  randomFloatScaleConstant = 4.656612873077392578125e-10;
  40.  
  41. static char initialized = 0;
  42.  
  43. RNG::RNG()
  44. {
  45.   if (!initialized)
  46.   {
  47.  
  48.     assert (sizeof(double) == 2 * sizeof(unsigned long)); 
  49.  
  50.     //
  51.     //    The following is a hack that I attribute to
  52.     //    Andres Nowatzyk at CMU. The intent of the loop
  53.     //    is to form the smallest number 0 <= x < 1.0,
  54.     //    which is then used as a mask for two longwords.
  55.     //    this gives us a fast way way to produce double
  56.     //    precision numbers from longwords.
  57.     //
  58.     //    I know that this works for IEEE and VAX floating
  59.     //    point representations.
  60.     //
  61.     //    A further complication is that gnu C will blow
  62.     //    the following loop, unless compiled with -ffloat-store,
  63.     //    because it uses extended representations for some of
  64.     //    of the comparisons. Thus, we have the following hack.
  65.     //    If we could specify #pragma optimize, we wouldn't need this.
  66.     //
  67.  
  68.     PrivateRNGDoubleType t;
  69.     PrivateRNGSingleType s;
  70.  
  71. #if _IEEE == 1
  72.     
  73.     t.d = 1.5;
  74.     if ( t.u[1] == 0 ) {        // sun word order?
  75.         t.u[0] = 0x3fffffff;
  76.         t.u[1] = 0xffffffff;
  77.     }
  78.     else {
  79.         t.u[0] = 0xffffffff;    // encore word order?
  80.         t.u[1] = 0x3fffffff;
  81.     }
  82.  
  83.     s.u = 0x3fffffff;
  84. #else
  85.     volatile double x = 1.0; // volatile needed when fp hardware used,
  86.                              // and has greater precision than memory doubles
  87.     double y = 0.5;
  88.     do {                // find largest fp-number < 2.0
  89.         t.d = x;
  90.         x += y;
  91.         y *= 0.5;
  92.     } while (x != t.d && x < 2.0);
  93.  
  94.     volatile float xx = 1.0; // volatile needed when fp hardware used,
  95.                              // and has greater precision than memory floats
  96.     float yy = 0.5;
  97.     do {                // find largest fp-number < 2.0
  98.         s.s = xx;
  99.         xx += yy;
  100.         yy *= 0.5;
  101.     } while (xx != s.s && xx < 2.0);
  102. #endif
  103.     // set doubleMantissa to 1 for each doubleMantissa bit
  104.     doubleMantissa.d = 1.0;
  105.     doubleMantissa.u[0] ^= t.u[0];
  106.     doubleMantissa.u[1] ^= t.u[1];
  107.  
  108.     // set singleMantissa to 1 for each singleMantissa bit
  109.     singleMantissa.s = 1.0;
  110.     singleMantissa.u ^= s.u;
  111.  
  112.     initialized = 1;
  113.     }
  114. }
  115.  
  116. float RNG::asFloat()
  117. {
  118.     PrivateRNGSingleType result;
  119.     result.s = 1.0;
  120.     result.u |= (asLong() & singleMantissa.u);
  121.     result.s -= 1.0;
  122.     assert( result.s < 1.0 && result.s >= 0);
  123.     return( result.s );
  124. }
  125.     
  126. double RNG::asDouble()
  127. {
  128.     PrivateRNGDoubleType result;
  129.     result.d = 1.0;
  130.     result.u[0] |= (asLong() & doubleMantissa.u[0]);
  131.     result.u[1] |= (asLong() & doubleMantissa.u[1]);
  132.     result.d -= 1.0;
  133.     assert( result.d < 1.0 && result.d >= 0);
  134.     return( result.d );
  135. }
  136.  
  137.